#include "stdio.h"
#include "stdint.h"
#include "string.h"
#include "cJSON.h"
#include "DevicesCRC.h"
#include "DevicesQueue.h"
#include "FeedPhy.h"
#include "FeedFrame.h"
#include "FeedID.h"
#include "FeedJson.h"
#include "FeedPack.h"


FeedPackType g_typeFeedPackUart1;


int8_t cFeedPackFrameSend(uint8_t ucChannelSend, uint8_t ucChannelPhy, uint8_t ucChannelLogic);
int8_t cFeedPackJsonSend(uint8_t ucChannelPhy, uint8_t ucChannelLogic);


int8_t cFeedPackEncode(FeedPackType *ptypePack)
{
    uint16_t usCrc;

    if(ptypePack == NULL)
        return 1;

    ptypePack->head[0] = 0x55;
    ptypePack->head[1] = 0xAA;

    usCrc = usCRC16_MODBUS(NULL, ptypePack, ptypePack->length + 6);

    ptypePack->datas[ptypePack->length]     = usCrc;
    ptypePack->datas[ptypePack->length + 1] = usCrc >> 8;

    return 0;
}

FeedPackStateEnum enumFeedPackDecode(FeedPackType *ptypePack, uint8_t ucByte)
{
    if(ptypePack == NULL)
        return 1;

    if(ptypePack->state == FEED_PACK_STATE_END)
    {
        ptypePack->state = FEED_PACK_STATE_HEAD0;
    }

    switch(ptypePack->state)
    {
        case FEED_PACK_STATE_HEAD0:
            ptypePack->head[0] = ucByte;
            ptypePack->state = (ucByte == 0x55) ? FEED_PACK_STATE_HEAD1 : FEED_PACK_STATE_HEAD0;
        break;

        case FEED_PACK_STATE_HEAD1:
            ptypePack->head[1] = ucByte;
            ptypePack->state = (ucByte == 0xAA) ? FEED_PACK_STATE_NO : ((ucByte == 0x55) ? FEED_PACK_STATE_HEAD1 : FEED_PACK_STATE_HEAD0);
        break;

        case FEED_PACK_STATE_NO:
            ptypePack->No = ucByte;
            ptypePack->state = FEED_PACK_STATE_TYPE;
        break;

        case FEED_PACK_STATE_TYPE:
            ptypePack->channelPhy = ucByte & 0x0F;
            ptypePack->channelLogic = ucByte >> 4;
            ptypePack->state = FEED_PACK_STATE_LENGTH_LOW;
        break;

        case FEED_PACK_STATE_LENGTH_LOW:
            ptypePack->length = ucByte;
            ptypePack->state = FEED_PACK_STATE_LENGTH_HIGH;
        break;

        case FEED_PACK_STATE_LENGTH_HIGH:
            ptypePack->length |= ((uint16_t)ucByte << 8);
            ptypePack->state = (ptypePack->length == 0) ? FEED_PACK_STATE_CRC_LOW : ((ptypePack->length <= sizeof(ptypePack->datas)) ? FEED_PACK_STATE_DATAS : FEED_PACK_STATE_HEAD0);
            ptypePack->cnt = 0;
        break;

        case FEED_PACK_STATE_DATAS:
            ptypePack->datas[ptypePack->cnt++] = ucByte;
            ptypePack->state = (ptypePack->cnt < ptypePack->length) ? FEED_PACK_STATE_DATAS : FEED_PACK_STATE_CRC_LOW;
        break;

        case FEED_PACK_STATE_CRC_LOW:
            ptypePack->crc = ucByte;
            ptypePack->state = FEED_PACK_STATE_CRC_HIGH;
        break;

        case FEED_PACK_STATE_CRC_HIGH:
            ptypePack->crc |= ((uint16_t)ucByte << 8);
            ptypePack->state = (ptypePack->crc == usCRC16_MODBUS(NULL, ptypePack, ptypePack->length + 6)) ? FEED_PACK_STATE_END : FEED_PACK_STATE_HEAD0;
        break;

        default: break;
    }

    return ptypePack->state;
}

int8_t cFeedPackAnalysis(uint32_t uiChannel, void *pvDatas, int32_t iLength)
{
    FeedPackType *ptypePack = &g_typeFeedPackUart1;
    uint8_t *pucDatas = pvDatas;
    int32_t i;

    /* 清空缓存 */
    enumQueueClear(&g_TypeQueueFeedSend);

    /* 与设备通信，以TLV格式 */
    if(uiChannel == FEED_PHY_CHANNEL_UART1)
    {
        for(i = 0; i < iLength; ++i)
        {
            if(enumFeedPackDecode(ptypePack, pucDatas[i]) == FEED_PACK_STATE_END)
            {
                /* 模组 */
                if(ptypePack->channelLogic == 0)
                {
                    cFeedFrameDecode(ptypePack->datas, ptypePack->length);
                    cFeedPackFrameSend(uiChannel, uiChannel, ptypePack->channelLogic);
                }
                /* 用户 */
                else
                {
                    /* 转换成 JSON 格式，再转发给云端、APP */
                    cFeedPhyDatasAdd(ptypePack->datas, ptypePack->length);
                    cFeedPackJsonSend(ptypePack->channelPhy, ptypePack->channelLogic);
                }
            }
        }
    }
    /* 与云端、APP通信，以JSON格式 */
    else
    {
        if(cFeedJsonDecode(pvDatas, iLength) == 1)
        {
            cFeedPackFrameSend(FEED_PHY_CHANNEL_UART1, uiChannel, 1);
        }
        else
        {
            cFeedPackJsonSend(uiChannel, 0);
        }
    }

    return 0;
}

int8_t cFeedPackFrameSend(uint8_t ucChannelSend, uint8_t ucChannelPhy, uint8_t ucChannelLogic)
{
    static uint32_t st_uiNo = 0;
    FeedPackType typePack;
    FeedFrameType typeFrame;
    int32_t iLength;

    typePack.length = 0;
    typePack.channelPhy = ucChannelPhy;
    typePack.channelLogic = ucChannelLogic;

    /* 回复数据 */
    while(iQueueGetLength(&g_TypeQueueFeedSend) > 1)
    {
        enumQueuePopDatas(&g_TypeQueueFeedSend, &typeFrame, 2);

        iLength = 2;
        if((typeFrame.get == 0) || (typeFrame.response == 1))
        {
            enumQueuePopDatas(&g_TypeQueueFeedSend, (uint8_t *)&typeFrame + 2, 2);
            iLength = typeFrame.length + 4;
        }

        /* 缓存已满 */
        if(iLength > (sizeof(typeFrame.datas) - typePack.length))
        {
            typePack.No = st_uiNo++;
            cFeedPackEncode(&typePack);
            cFeedPhyDatasSend(ucChannelSend, &typePack, typePack.length + 8);

            typePack.length = 0;
        }

        enumQueuePopDatas(&g_TypeQueueFeedSend, typeFrame.datas, iLength - 4);
        memcpy(&typePack.datas[typePack.length], &typeFrame, iLength);

        typePack.length += iLength;
    }

    if(typePack.length > 0)
    {
        typePack.No = st_uiNo++;
        cFeedPackEncode(&typePack);
        cFeedPhyDatasSend(ucChannelSend, &typePack, typePack.length + 8);
    }

    return 0;
}

int8_t cFeedPackJsonSend(uint8_t ucChannelPhy, uint8_t ucChannelLogic)
{
    cJSON *pjsonRoot, *pjsonChannel, *pjsonResponse, *pjsonResponseSet, *pjsonResponseGet, *pjsonOut;
    char *pcPrints;
    FeedFrameType typeFrame;
    char cID[6] = {0};

    pjsonRoot        = cJSON_CreateObject();
    pjsonChannel     = cJSON_CreateObject();
    pjsonResponse    = cJSON_CreateObject();
    pjsonResponseSet = cJSON_CreateObject();
    pjsonResponseGet = cJSON_CreateObject();
    if((pjsonRoot == NULL) || (pjsonChannel == NULL) || (pjsonResponse == NULL) || (pjsonResponseSet == NULL) || (pjsonResponseGet == NULL))
    {
        cJSON_Delete(pjsonRoot);
        cJSON_Delete(pjsonChannel);
        cJSON_Delete(pjsonResponse);
        cJSON_Delete(pjsonResponseSet);
        cJSON_Delete(pjsonResponseGet);
        return 1;
    }

    /* 回复数据 */
    while(iQueueGetLength(&g_TypeQueueFeedSend) > 4)
    {
        enumQueuePopDatas(&g_TypeQueueFeedSend, &typeFrame, 4);
        enumQueuePopDatas(&g_TypeQueueFeedSend, typeFrame.datas, typeFrame.length);
        typeFrame.datas[typeFrame.length] = 0;

        /* 转换成JSON格式 */
        if(iFeedFrameToJson(&pjsonOut, &typeFrame) == 0)
        {
            snprintf(cID, sizeof(cID), "%d", typeFrame.ID);
            if(cJSON_AddItemToObject((typeFrame.get == 0) ? pjsonResponseSet : pjsonResponseGet, cID, pjsonOut) == 0)
            {
                cJSON_Delete(pjsonOut);
            }
        }
    }

    /* set响应 */
    if(pjsonResponseSet->child != NULL)
        cJSON_AddItemToObjectCS(pjsonResponse, "set_res", pjsonResponseSet);
    else
        cJSON_Delete(pjsonResponseSet);

    /* get响应 */
    if(pjsonResponseGet->child != NULL)
        cJSON_AddItemToObjectCS(pjsonResponse, "get_res", pjsonResponseGet);
    else
        cJSON_Delete(pjsonResponseGet);

    /* ID */
    if(pjsonResponse->child != NULL)
        cJSON_AddItemToObjectCS(pjsonChannel, "ID", pjsonResponse);
    else
        cJSON_Delete(pjsonResponse);

    /* 通道 */
    if(pjsonChannel->child != NULL)
    {
        snprintf(cID, sizeof(cID), "%d", ucChannelLogic);
        cJSON_AddItemToObjectCS(pjsonRoot, cID, pjsonChannel);
    }
    else
        cJSON_Delete(pjsonChannel);

    if(pjsonRoot->child != NULL)
    {
        if((pcPrints = cJSON_PrintUnformatted(pjsonRoot)) != NULL)
        {
            cFeedPhyDatasSend(ucChannelPhy, pcPrints, strlen(pcPrints));
            /* 结束符：\r */
            cFeedPhyDatasSend(ucChannelPhy, "\r", 1);

            cJSON_free(pcPrints);
        }
    }

    cJSON_Delete(pjsonRoot);

    return 0;
}
